/*
 * The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License");  you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * http//www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * The Original Code is ONTOLING_PROTEGE.
 *
 * The Initial Developer of the Original Code is University of Roma Tor Vergata.
 * Portions created by University of Roma Tor Vergata are Copyright (C) 2009.
 * All Rights Reserved.
 *
 * ONTOLING_PROTEGE was developed by the Artificial Intelligence Research Group
 * (ai-nlp.info.uniroma2.it) at the University of Roma Tor Vergata
 * Current information about ONTOLING_PROTEGE can be obtained at 
 * http//ai-nlp.info.uniroma2.it/software/...
 *
 */

/*
 * Contributor(s): Armando Stellato stellato@info.uniroma2.it
 */
package it.uniroma2.art.ontoling.protege.ui;

import it.uniroma2.art.lw.config.ui.LoaderFrame;
import it.uniroma2.art.lw.manager.LinguisticWatermarkManager;
import it.uniroma2.art.lw.model.objects.ExclusiveExplorationObject;
import it.uniroma2.art.lw.model.objects.LexicalRelation;
import it.uniroma2.art.lw.model.objects.SearchFilter;
import it.uniroma2.art.lw.model.objects.SearchStrategy;
import it.uniroma2.art.lw.model.objects.SearchWord;
import it.uniroma2.art.lw.model.objects.SemanticRelation;
import it.uniroma2.art.ontoling.OntoLingCore;
import it.uniroma2.art.ontoling.exceptions.UIActionException;
import it.uniroma2.art.ontoling.model.OntResourceType;
import it.uniroma2.art.ontoling.protege.OntoLingTab;
import it.uniroma2.art.ontoling.protege.util.PseudoLogger;
import it.uniroma2.art.ontoling.protege.util.Util;
import it.uniroma2.art.ontoling.ui.CMOption;
import it.uniroma2.art.ontoling.ui.CMOptionList;
import it.uniroma2.art.ontoling.ui.GUIAdapter;
import it.uniroma2.art.ontoling.ui.UIAction;
import it.uniroma2.art.ontoling.ui.UIActionList;
import it.uniroma2.art.ontoling.ui.UIReasoner;
import it.uniroma2.art.ontoling.ui.UIAction.ContextMenuSetter;
import it.uniroma2.art.ontoling.ui.UIAction.GlossTextSetter;
import it.uniroma2.art.ontoling.ui.UIAction.RelationExplorerSetter;
import it.uniroma2.art.ontoling.ui.UIAction.ResultTableHeadersSetter;
import it.uniroma2.art.ontoling.ui.UIAction.ResultTableSetter;
import it.uniroma2.art.ontoling.ui.UIAction.SearchFilterMarker;
import it.uniroma2.art.ontoling.ui.UIAction.SearchFiltersSetter;
import it.uniroma2.art.ontoling.ui.UIAction.SearchTextSetter;
import it.uniroma2.art.ontoling.ui.UIAction.SearchWordsSetter;
import it.uniroma2.art.ontoling.ui.UIAction.SemanticIndexTextSetter;
import it.uniroma2.art.ontoling.ui.UIAction.SynonymsListSetter;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JPopupMenu;
import javax.swing.JSeparator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.stanford.smi.protege.model.Cls;
import edu.stanford.smi.protege.model.Frame;
import edu.stanford.smi.protege.model.Slot;
import edu.stanford.smi.protege.util.SelectableContainer;
import edu.stanford.smi.protege.util.TreePopupMenuMouseListener;

public class ProtegeGUIAdapter extends GUIAdapter {

	private Linguistic_GUI lgui;
	private OntologyPanel ontPanel;
	private SubclassPane subClassPane;
	private SubslotPane subSlotPane;
	private GUI_Facade guiFacade;

	private SearchWord searchWord = null;

	protected static Log logger = LogFactory.getLog(ProtegeGUIAdapter.class);

	private HashMap<Class<? extends ExclusiveExplorationObject>, JComboBox> relationExplorers;

	public ProtegeGUIAdapter() {
		this.lgui = GUI_Manager.getLinguisticGUI();
		this.ontPanel = GUI_Manager.getOntologyPanel();
		subClassPane = ontPanel.getInstanceOfClsesPanel().getSubclassPane();
		subSlotPane = ontPanel.getInstanceOfSubslotPane();
		guiFacade = OntoLingTab.getOntoLingTab().getGUIFacade();

		relationExplorers = new HashMap<Class<? extends ExclusiveExplorationObject>, JComboBox>();
		relationExplorers.put(SemanticRelation.class, lgui.CRelFindCBx);
		relationExplorers.put(LexicalRelation.class, lgui.LRelFindCBx);
		relationExplorers.put(SearchStrategy.class, lgui.SearchStrategyCBx);
	}

	// TODO ALL OTHER METHODS SHOULD PASS THROUGH GUIFACADE AS THIS ONE, INSTEAD OF WRITING DIRECTLY OVER THE
	// GUI
	@Override
	public void carryUIAction(SearchTextSetter sts) {
		guiFacade.setSearchFieldText(sts.getTextToSet());
	}

	@Override
	public void carryUIAction(GlossTextSetter gts) {
		guiFacade.setGlossAreaText(gts.getTextToSet());
	}

	@Override
	public void carryUIAction(SemanticIndexTextSetter cts) {
		guiFacade.setSemanticIndexFieldText(cts.getTextToSet());
	}

	@Override
	public void carryUIAction(SynonymsListSetter sls) {
		List<String> synonyms = sls.getSynonyms();
		String selWord = sls.getSelectedWord();
		guiFacade.setSynonymsList(synonyms, selWord);
	}

	@Override
	public void carryUIAction(ResultTableSetter rts) {
		ArrayList<String[]> results = rts.getResultsList();
		guiFacade.setResultTable(results);
	}

	@Override
	protected <T extends ExclusiveExplorationObject> void carryUIAction(RelationExplorerSetter<T> res) {
		Collection<T> relations = res.getRelations();
		JComboBox tempBox = relationExplorers.get(res.getType());
		if (relations != null) {
			for (T relation : relations)
				tempBox.addItem(relation.getName());
		} else {
			tempBox.setEnabled(false);
			tempBox.setToolTipText("no entries of this type in loaded Linguistic Interface");
		}
	}

	@Override
	protected void carryUIAction(ResultTableHeadersSetter rths) {
		ResultsTableModel tm = (ResultsTableModel) lgui.ResultsTable.getModel();

		String kc = rths.getKeyColumn();
		if (kc != null)
			tm.setColumnName(kc, 0);

		String vc = rths.getValueColumn();
		if (vc != null)
			tm.setColumnName(vc, 1);

		tm.fireTableStructureChanged();

		String tt = rths.getToolTip();
		if (tt != null)
			lgui.ResultsTable.setToolTipText(tt);
	}

	@Override
	protected void carryUIAction(SearchFiltersSetter sfs) {
		if (sfs.getSearchFilters() != null)
			for (SearchFilter sf : sfs.getSearchFilters()) {
				lgui.addFilterBox(sf);
			}
	}

	@Override
	protected void carryUIAction(SearchFilterMarker sfm) {
		logger.info("dentro carryUIAction con SearchFilterMarker di ProtegeGUIAdapter");
	}

	@Override
	protected void carryUIAction(ContextMenuSetter ctxSetter) {
		final CMOptionList ctxMenu = ctxSetter.getContextMenu();
		// JPopupMenu menu;

		OntoLingOntoTree subResPane = null;

		if (ctxMenu.getResType() == OntResourceType.cls)
			subResPane = subClassPane;
		if (ctxMenu.getResType() == OntResourceType.prop)
			subResPane = subSlotPane;
		if (ctxMenu.getResType() == OntResourceType.inst)
			return;

		JPopupMenu menu = subResPane.createStdPopupMenu();
		ArrayList<ActionEnabler> actionsList = new ArrayList<ActionEnabler>();

		for (CMOption opt : ctxMenu) {

			if (opt instanceof CMOption.AddGloss) {
				final String label = opt.getLabel();
				final Action addGloss = subResPane.addGloss(label);
				actionsList.add(new ActionEnabler(addGloss, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) addGloss).putValue("Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(addGloss);
			}

			else if (opt instanceof CMOption.AddTerms) {
				final String label = opt.getLabel();
				final Action addTerms = subResPane.addTerms(label);
				actionsList.add(new ActionEnabler(addTerms, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) addTerms).putValue("Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(addTerms);
			}

			else if (opt instanceof CMOption.MenuSeparator) {
				addSeparator(menu);
			}

			else if (opt instanceof CMOption.AddSenseIdToResource) {
				final String label = opt.getLabel();
				final Action addSenseIdToResource = subResPane.addSenseIdToResource(label);
				actionsList.add(new ActionEnabler(addSenseIdToResource, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) addSenseIdToResource).putValue("Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(addSenseIdToResource);
			}

			else if (opt instanceof CMOption.SearchLinguisticResource) {
				final String label = opt.getLabel();
				final Action searchLinguisticResource = subResPane.searchLinguisticResource(label);
				actionsList.add(new ActionEnabler(searchLinguisticResource, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) searchLinguisticResource).putValue("Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}

				});
				menu.add(searchLinguisticResource);
			}

			else if(ctxMenu.getResType() != OntResourceType.cls)
				continue; //the following possibilities are only for the class Panel
			
			else if (opt instanceof CMOption.ChangeNameToSelectedTerm) {
				final String label = opt.getLabel();
				final Action changeNameToSelectedTerm = subResPane.changeNameToSelectedTerm(label);
				actionsList.add(new ActionEnabler(changeNameToSelectedTerm, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) changeNameToSelectedTerm).putValue("Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(changeNameToSelectedTerm);
			}

			else if (opt instanceof CMOption.CreateSubResourceWithSelectedTermAsID) {
				final String label = opt.getLabel();
				final Action createSubResourceWithSelectedTermAsID = subResPane
						.createSubResourceWithSelectedTermAsID(label);
				actionsList.add(new ActionEnabler(createSubResourceWithSelectedTermAsID, subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) createSubResourceWithSelectedTermAsID).putValue("Name",
								lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(createSubResourceWithSelectedTermAsID);
			}

			else if (opt instanceof CMOption.AddSubResourcesUsingSubConceptsFromLinguisticResources) {
				final String label = opt.getLabel();
				final Action addSubResourcesUsingSubConceptsFromLinguisticResources = subResPane
						.addSubResourcesUsingSubConceptsFromLinguisticResources(label);
				actionsList.add(new ActionEnabler(addSubResourcesUsingSubConceptsFromLinguisticResources,
						subResPane) {
					@Override
					public void updateEnable() {
						LabelEnabled lableEnabled = setMenuItem(label, subResPane);
						((AbstractAction) addSubResourcesUsingSubConceptsFromLinguisticResources).putValue(
								"Name", lableEnabled.getLabel());
						action.setEnabled(lableEnabled.getEnabled());
					}
				});
				menu.add(addSubResourcesUsingSubConceptsFromLinguisticResources);
			}

			/*
			 * LING_ENRICH
			 * 
			 * else if (opt instanceof CMOption.CallLinguisticEnrichment) { final String label =
			 * opt.getLabel(); final Action callLinguisticEnrichment =
			 * subResPane.callLinguisticEnrichment(label); actionsList.add( new
			 * ActionEnabler(callLinguisticEnrichment, subResPane) {
			 * 
			 * @Override public void updateEnable() { LabelEnabled lableEnabled = setMenuItem(label,
			 * subResPane);
			 * ((AbstractAction)callLinguisticEnrichment).putValue("Name",lableEnabled.getLabel());
			 * action.setEnabled(lableEnabled.getEnabled()); } }); menu.add( callLinguisticEnrichment ); }
			 */

		}

		subResPane.getTree().addMouseListener(new ClassTreePopupMenuMouseListener(subResPane, actionsList));

		subResPane.setPopupMenu(menu);

	}

	@Override
	protected void carryUIAction(SearchWordsSetter searchWordsetter) {
		final UIReasoner ui = OntoLingCore.getOntoLingCore().getUIReasoner();
		final GUIAdapter guiAdapter = OntoLingCore.getOntoLingCore().getGUIAdapter();

		// It is possible that there are different SearchWord that have the same String, so first of all it's
		// important
		// to eliminate the duplicates
		Collection<SearchWord> newSearchWords = new ArrayList<SearchWord>();
		Collection<String> searchWordAddedString = new ArrayList<String>();

		Iterator<SearchWord> iter = searchWordsetter.getSearchWords().iterator();
		while (iter.hasNext()) {
			SearchWord searchWord = iter.next();
			if (!searchWordAddedString.contains(searchWord.getName())) {
				newSearchWords.add(searchWord);
				searchWordAddedString.add(searchWord.getName());
			}
		}

		if (newSearchWords.size() > 1) {
			final SearchWordsFrame searchWordsFrame = new SearchWordsFrame(newSearchWords);
			searchWordsFrame.setVisible(true);

			JButton jbuttonOK = searchWordsFrame.getOKButton();
			jbuttonOK.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent arg0) {
					searchWord = searchWordsFrame.getSelection();
					UIActionList al;
					searchWordsFrame.dispose();
					try {
						al = ui.notifiedSearchWord(searchWord);
						guiAdapter.handleUIActionList(al);
					} catch (UIActionException e) {
						OntoLingTab.getOntoLingTab().getGUIFacade().showErrorMessage(e);
					}
				}
			});
		} else if (newSearchWords.size() == 1) {
			searchWord = newSearchWords.iterator().next();
			try {
				UIActionList al;
				al = ui.notifiedSearchWord(searchWord);
				guiAdapter.handleUIActionList(al);
			} catch (UIActionException e) {
				OntoLingTab.getOntoLingTab().getGUIFacade().showErrorMessage(e);
			}
		} else {
			searchWord = null;
			try {
				UIActionList al;
				al = ui.notifiedSearchWord(searchWord);
				guiAdapter.handleUIActionList(al);
			} catch (UIActionException e) {
				OntoLingTab.getOntoLingTab().getGUIFacade().showErrorMessage(e);
			}
		}

	}

	/*
	 * public SearchWord getSearchWord(){ return searchWord; }
	 */

	public abstract class ActionEnabler {

		protected Action action;
		protected OntoLingOntoTree subResPane;

		ActionEnabler(Action action, OntoLingOntoTree subResPane) {
			this.subResPane = subResPane;
			this.action = action;
		}

		public abstract void updateEnable();
	}

	public class ClassTreePopupMenuMouseListener extends TreePopupMenuMouseListener {

		OntoLingOntoTree subResPane;
		ArrayList<ActionEnabler> actionList;

		protected ClassTreePopupMenuMouseListener(OntoLingOntoTree subResPane,
				ArrayList<ActionEnabler> actionList) {
			super(subResPane.getTree());
			this.subResPane = subResPane;
			this.actionList = actionList;
		}

		@Override
		protected JPopupMenu getPopupMenu() {
			for (ActionEnabler enabler : actionList)
				enabler.updateEnable();
			return subResPane.getPopupMenu();
		}

	}

	/*
	 * new TreePopupMenuMouseListener(subClassPane.getTree() ) { public JPopupMenu getPopupMenu() { return
	 * subClassPane.getPopupMenu(); } }
	 */

	private void addSeparator(JPopupMenu menu) {
		// never add two separators in a row
		int count = menu.getComponentCount();
		Component c = menu.getComponent(count - 1);
		if (!(c instanceof JSeparator)) {
			menu.addSeparator();
		}
	}

	@Override
	protected void carryUIAction(UIAction sts) {
	}

	private LabelEnabled setMenuItem(String label, OntoLingOntoTree subResPane) {
		LabelEnabled labelEnabled = null;
		String newLabel = label;
		Boolean enabled = true;
		
		if (label.contains(CMOption.GLOSS)) {
			newLabel = newLabel.replace(CMOption.GLOSS, "gloss");
			if (guiFacade.getDescription().length() == 0)
				enabled = false;
		}
		if (label.contains(CMOption.ENTRY_TABLE)) {

		}
		if (label.contains(CMOption.STRING_SEARCH)) {

		}
		if (label.contains(CMOption.SENSE_ID)) {
			String senseID = guiFacade.getSelectedSemex();
			if (senseID == null)
				enabled = false;
			else
				newLabel = newLabel.replace(CMOption.SENSE_ID, "\"" + senseID + "\"");

		}
		if (label.contains(CMOption.TERMS)) {

		}
		if (label.contains(CMOption.SLOT)) {
			if(Util.kbInOWL(subClassPane.getKnoledgeBase()))
				newLabel = newLabel.replace(CMOption.SLOT, "");
			else{
				Frame res = (Frame) ((SelectableContainer) subResPane).getSoleSelection();
				Slot slottino = ontPanel.getTerminologySlot();
				if ((slottino == null) || (res.hasOwnSlot(slottino) == false)
						|| (guiFacade.getSelectedWord() == null))
					enabled = false;
				else
					newLabel = newLabel.replace(CMOption.SLOT, "\"" + slottino.getName() + "\"");
			}
		}
		if (label.contains(CMOption.SELECTED_TERM)) {
			String selTerm = guiFacade.getSelectedWord();
			if (selTerm == null) {
				enabled = false;
			} else
				newLabel = newLabel.replace(CMOption.SELECTED_TERM, "\"" + selTerm + "\"");
		}
		if (label.contains(CMOption.SELECTED_RES)) {
			String selResString = null;
			if (subResPane instanceof SubclassPane)
				selResString = ((SubclassPane) subResPane).getSelectedClass();
			else if (subResPane instanceof SubslotPane)
				selResString = ((SubslotPane) subResPane).getSelectedProp();
			
			if (selResString == null)
				enabled = false;
			else{
				if(selResString.indexOf("#") != -1)
					selResString = selResString.substring(selResString.indexOf("#")+1);
				else if(selResString.indexOf(":") != -1)
					selResString = selResString.substring(selResString.indexOf(":")+1);
				newLabel = newLabel.replace(CMOption.SELECTED_RES, "\"" + selResString + "\"");
			}
			
		}
		/*
		 * if(label.contains(CMOption.LING_ENRICH)){ newLabel = newLabel.replace(CMOption.LING_ENRICH, "");
		 * if(EnrichmentPanel.getInstanceOfLinguisticEnricherWrapper() == null) enabled = false; else
		 * if(EnrichmentPanel.getInstanceOfLinguisticEnricherWrapper().hasStarted() == false) enabled= false;
		 * }
		 */
		
		labelEnabled = new LabelEnabled(newLabel, enabled);

		return labelEnabled;
	}

	private static class LabelEnabled {
		private String label;
		private boolean enabled;

		public LabelEnabled(String label, boolean enabled) {
			this.label = label;
			this.enabled = enabled;
		}

		public String getLabel() {
			return label;
		}

		public boolean getEnabled() {
			return enabled;
		}
	}

}
